#include "input.h"

//loaders and the like
#include "colladaLoader.h"
#include "spriteMeshLoader.h"

//actors
#include "particleSystem.h"
#include "physicsActor.h"
#include "ragDoll.h"
#include "skeletalActor.h"
#include "hitBox.h"
#include "cameraActor.h"
#include "spriteCharacter.h"
#include "boneActor.h"
#include "skeletalDrawing.h"
#include "skeletalHead.h"
#include "videoTextureActor.h"

//buttons
#include "console.h"
#include "createActorButton.h"
#include "createDrawingButton.h"
#include "createNodeButton.h"
#include "moveButton.h"
#include "rotateButton.h"
#include "listButton.h"
#include "sliderButton.h"
#include "saveButton.h"
#include "loadButton.h"
#include "getActorButton.h"

#include "makeGridButton.h"
#include "drawingWidget.h"
#include "newDrawingButton.h"
#include "pencilButton.h"
#include "selectDrawingButton.h"
#include "importBitmapButton.h"
#include "loadBrushButton.h"
#include "saveDrawingButton.h"
#include "loadDrawingButton.h"
#include "connectBrushButton.h"
#include "loadDrawSkeletonButton.h"

#include "assignButton.h"
#include "propertyAssignButton.h"
#include "textInputButton.h"
#include "colorPickButton.h"
#include "pickWorldButton.h"

//static buttons for windows and messages and stuff
#include "createPrefabButton.h"
#include "createActionButton.h"



//inspectors
#include "propertyInspector.h"
#include "textureInspector.h"
#include "actionInspector.h"
#include "timelineInspector.h"
#include "meshInspector.h"
#include "prefabInspector.h"

#include "timelineButton.h"

//communication
#include "udpInput.h"

//nodes
#include "node.h"
#include "rootNode.h"
#include "waitForTimerNode.h"
#include "interpolateNode.h"
#include "keyInputNode.h"
#include "switchCameraNode.h"
#include "performActionNode.h"
#include "setPropertyNode.h"
//animation
#include "action.h"
#include "particleSystemCS.h"

//verion
#include "swansee.h"

//static link
Renderer* Renderer::rendererInstance=NULL;

//************************************************************
//
//RTTY actorInfo - Information about every Actor:
//                 Class Name, Type, Size
//
//************************************************************


void Renderer::fillGlobalLists(){



    //actors
    Actor *A;
    A= new Actor;
    createActorID(A);

    //------ video test
    VideoTextureActor * VTA;
    VTA=new VideoTextureActor;
    createActorID(VTA);

    //------

    ParticleSystem *P;
    P= new ParticleSystem;
    createActorID(P);

    ParticleSystemCS *PCS;
    PCS= new ParticleSystemCS;
    createActorID(PCS);

    RagDoll *Rag;
    Rag= new RagDoll;
    createActorID(Rag);

    SkeletalActor *Skel;
    Skel=new SkeletalActor;
    createActorID(Skel);

    SkeletalDrawing *skelDraw;
    skelDraw=new SkeletalDrawing;
    createActorID(skelDraw);

    SkeletalHead *skelHead;
    skelHead=new SkeletalHead;
    createActorID(skelHead);

    Brush *Bru;
    Bru=new Brush;
    createActorID(Bru);

    CameraActor *camAct;
    camAct=new CameraActor;
    createActorID(camAct);

    HitBox *hb;
    hb=new HitBox;
    createActorID(hb);

    SpriteCharacter *sprChr;
    sprChr=new SpriteCharacter;
    createActorID(sprChr);

    BoneActor *bAct;
    bAct=new BoneActor;
    createActorID(bAct);


    Swansee *sw;
    sw=new Swansee;
    createActorID(sw);


    ////buttons
    msbButton::Button *B;
    B= new msbButton::Button;
    createActorID(B);

    Console *C;
    C= new Console;
    createActorID(C);

    NavButton *navBtn;
    navBtn=new NavButton;
    createActorID(navBtn);

    CreateActorButton *creBtn;
    creBtn=new CreateActorButton;
    createActorID(creBtn);

    CreateDrawingButton *creDrBtn;
    creDrBtn=new CreateDrawingButton;
    createActorID(creDrBtn);

    CreateNodeButton *creNodeBtn;
    creNodeBtn=new CreateNodeButton;
    createActorID(creNodeBtn);

    ListButton *listBtn;
    listBtn=new ListButton;
    createActorID(listBtn);

    SliderButton *slideBtn;
    slideBtn=new SliderButton;
    createActorID(slideBtn);

    SaveButton *saveBtn;
    saveBtn=new SaveButton;
    createActorID(saveBtn);

    LoadButton *loadBtn;
    loadBtn=new LoadButton;
    createActorID(loadBtn);

    MoveButton *movBtn;
    movBtn=new MoveButton;
    createActorID(movBtn);

    RotateButton *rotBtn;
    rotBtn=new RotateButton;
    createActorID(rotBtn);

    GetActorButton *getBtn;
    getBtn=new GetActorButton;
    createActorID(getBtn);

    MakeGridButton *mkgrBtn;
    mkgrBtn=new MakeGridButton;
    createActorID(mkgrBtn);

    NewDrawingButton *newDrwBtn;
    newDrwBtn=new NewDrawingButton;
    createActorID(newDrwBtn);

    PencilButton *newPenBtn;
    newPenBtn=new PencilButton;
    createActorID(newPenBtn);

    SelectDrawingButton *selDrwBtn;
    selDrwBtn=new SelectDrawingButton;
    createActorID(selDrwBtn);

    ImportBitmapButton *impBtmpBtn;
    impBtmpBtn=new ImportBitmapButton;
    createActorID(impBtmpBtn);

    LoadBrushButton *ldBrshBtn;
    ldBrshBtn=new LoadBrushButton;
    createActorID(ldBrshBtn);


    SaveDrawingButton *savDrwBtn;
    savDrwBtn=new SaveDrawingButton;
    createActorID(savDrwBtn);

    LoadDrawingButton *lodDrwBtn;
    lodDrwBtn=new LoadDrawingButton;
    createActorID(lodDrwBtn);

    LoadDrawSkeletonButton *ldsb;
    ldsb=new LoadDrawSkeletonButton;
    createActorID(ldsb);

    DrawingWidget * drawWidge;
    drawWidge=new DrawingWidget;
    createActorID(drawWidge);

    PropertyAssignButton *propAssBtn;
    propAssBtn= new PropertyAssignButton;
    createActorID(propAssBtn);

    TextInputButton *newTxtInptBtn;
    newTxtInptBtn=new TextInputButton;
    createActorID(newTxtInptBtn);

    AssignButton *newAssignBtn;
    newAssignBtn=new AssignButton;
    createActorID(newAssignBtn);

    ColorPickButton *colPckBtn;
    colPckBtn=new ColorPickButton;
    createActorID(colPckBtn);

    PickWorldButton *pckWrlBtn;
    pckWrlBtn=new PickWorldButton;
    createActorID(pckWrlBtn);

    CreatePrefabButton *prefBtn;
    prefBtn=new CreatePrefabButton;
    createActorID(prefBtn);

    CreateActionButton *actBtn;
    actBtn=new CreateActionButton;
    createActorID(actBtn);

    UdpInput *newUdpInput;
    newUdpInput=new UdpInput;
    createActorID(newUdpInput);

    ConnectBrushButton *conBrush;
    conBrush=new ConnectBrushButton;
    createActorID(conBrush);

    PropertyInspector *propIn;
    propIn=new PropertyInspector;
    createActorID(propIn);

    //inspectors
    TextureInspector *texIn;
    texIn=new TextureInspector;
    createActorID(texIn);

    MeshInspector *meshIn;
    meshIn=new MeshInspector;
    createActorID(meshIn);

    ActionInspector *actIn;
    actIn=new ActionInspector;
    createActorID(actIn);

    PrefabInspector *pref;
    pref=new PrefabInspector;
    createActorID(pref);

    TimelineInspector *timeIn;
    timeIn=new TimelineInspector;
    createActorID(timeIn);

    TimelineButton *tlBut;
    tlBut=new TimelineButton;
    createActorID(tlBut);

    //actions
    Action *newAction;
    newAction=new Action;
    createActorID(newAction);

    //Nodes
    Node *newNode;
    newNode=new Node;
    createActorID(newNode);

    RootNode *newRootNode;
    newRootNode=new RootNode;
    createActorID(newRootNode);

    KeyInputNode *newKeyInput;
    newKeyInput=new KeyInputNode;
    createActorID(newKeyInput);

    WaitForTimerNode *newWtFrTmNode;
    newWtFrTmNode=new WaitForTimerNode;
    createActorID(newWtFrTmNode);

    InterpolateNode *newIntNode;
    newIntNode=new InterpolateNode;
    createActorID(newIntNode);

    SwitchCameraNode *newSwitchCam;
    newSwitchCam=new SwitchCameraNode;
    createActorID(newSwitchCam);

    PerformActionNode *newPerfAct;
    newPerfAct=new PerformActionNode;
    createActorID(newPerfAct);

    SetPropertyNode *setPropNode;
    setPropNode=new SetPropertyNode;
    createActorID(setPropNode);
}


//************************************************************
//
//Constructor and Destructor
//
//************************************************************

Renderer::Renderer(){


    backgroundTex="";
    backgroundColor=Vector4f(0.0,0.0,0.0,1);

    lastShader="NULL";

    startSceneFilename="";

    bUseFBO=true;                       //make sure we only use FBOs if the hardware
    bRenderShadow=true;
    bRenderSceneTexture=true;
    bDepthPass=false;
    bRenderStereo=true;
    bCollisionOnly=false;
    bShowMenu=true;
    bDrawHelpers=true;

    bUpdateTransform=true;
    bIncludeShadows=true;
    bIncludeTextures=true;

    bFullscreen=false;
    bUpdatePhysics=false;

    lightLoc=Vector3f(0,3,15);                  //light Location
    ambient=Vector3f(1,1,1);

    fov=45;
    nearClip=0.2;
    farClip=1000;
    frustumTop=0.083;
    frustumBottom=-0.083;

    eyeDistance=0.02;

    mouseSensitivity=0.005;
    moveSpeed=0.1;

    screenX=0;
    screenY=0;
    windowX=0;
    windowY=0;

    shadow_tx = 0; // the shadow texture
    shadow_fb = 0; // the framebuffer object to render to that texture
    shadow_db = 0;
    shadow_size = 512; // the shadow map size

    depth_tx = 0;
    depth_fb = 0;
    depth_db = 0;
    depth_size = 512;

    scene_tx = 0;
    scene_fb = 0;
    scene_db = 0;
    scene_size = 512;

    leftEye_tx = 0;
    leftEye_fb = 0;
    leftEye_db = 0;
    leftEye_size = 512;

    rightEye_tx = 0;
    rightEye_fb = 0;
    rightEye_db = 0;
    rightEye_size = 512;

    rightEyeFBO=NULL;
    leftEyeFBO=NULL;

    physicsWorld = dWorldCreate();          //create a default physics world
    collisionSpace = dHashSpaceCreate(0);   //create a default collision space
    dWorldSetGravity (physicsWorld,0,-9.81,0);
    jointGroup = dJointGroupCreate(0);
    groundPlane = dCreatePlane(collisionSpace,0,1,0,0);
}

Renderer::~Renderer(){

    if (bUseFBO){

        if (bRenderShadow){
            glDeleteRenderbuffersEXT(1, &shadow_db);
            glDeleteFramebuffersEXT(1, &shadow_tx);
        }


        if (bRenderSceneTexture){
            glDeleteRenderbuffersEXT(1, &depth_db);
            glDeleteFramebuffersEXT(1, &depth_tx);

            glDeleteRenderbuffersEXT(1, &scene_db);
            glDeleteFramebuffersEXT(1, &scene_tx);
            }
    }

    dSpaceDestroy(collisionSpace);
    dWorldDestroy(physicsWorld);
    dCloseODE();
}

Renderer* Renderer::getInstance(){

    if (rendererInstance)
        return rendererInstance;
    else{
        rendererInstance=new Renderer;
        return rendererInstance;
        }
}

//************************************************************
//
//  Windowing stuff and screen setup
//
//************************************************************

void Renderer::initWindow(int x, int y, char* windowName){

    //screenX=x;
    //screenY=y;
    input->screenX=screenX;
    input->screenY=screenY;
    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA );
//    glutInitDisplayString("rgba double depth>=24 sample=8");

    if (bFullscreen)
      {
      // 1024x768, 32bit pixel depth, 60Hz refresh rate
      char* gmString  = new char[64];
      sprintf(gmString," %ix%i:32@60",screenX,screenY);
      glutGameModeString( gmString );
      // start fullscreen game mode
      glutEnterGameMode();
      }
    else
      {
      glutInitWindowSize(x,y);
      glutInitWindowPosition(input->windowX,input->windowY);
      glutCreateWindow(windowName);
      }
}



void Renderer::reDrawScreen(int w, int h){

	// Prevent a divide by zero, when window is too short
	// (you cant make a window of zero width).
	if(h == 0)
		h = 1;

//	float ratio = 1.0* w / h;

	// Reset the coordinate system before modifying
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	// Set the viewport to be the entire window
	glViewport(0, 0, w, h);

	// Set the correct perspective.
	gluPerspective(fov,(screenY==0)?(1):((float)screenX/screenY),nearClip,farClip);
    glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(input->controller->controlledActor->location.x, input->controller->controlledActor->location.y,input->controller->controlledActor->location.z,
		      input->controller->lookPoint.x,input->controller->lookPoint.y,input->controller->lookPoint.z,
			  input->controller->upPoint.x, input->controller->upPoint.y,input->controller->upPoint.z);
    input->screenX=screenX;
    input->screenY=screenY;
}

// load render settings
void Renderer::loadPreferences(){

    input=Input::getInstance();
    colladaLoader=new ColladaLoader();
    spriteMeshLoader=new SpriteMeshLoader();

    //open config xml file
    //configure renderer
    cout << "Loading Config file" <<endl;

    TiXmlDocument doc( "config.xml" );
    if (!doc.LoadFile()) return;


    TiXmlHandle hDoc(&doc);
    TiXmlElement * element;
    TiXmlHandle hRoot(0);

    //***********************************************************************
    //Get the "Moviesandbox" element
    //***********************************************************************
    element=hDoc.FirstChildElement().Element();
    // should always have a valid root but handle gracefully if it doesn't
    if (!element) return;

    // save this for later
    hRoot=TiXmlHandle(element);

    //now load the configuration
    cout << "loading render settings" << endl;

    element=hRoot.FirstChild( "Rendersettings" ).Element();

    int val=0;
    double dVal=0.0;
    string mStr;

    //resolution
    element->Attribute("WindowSizeX", &val);
    windowX=val;
    element->Attribute("WindowSizeY", &val);
    windowY=val;

    //renderscreen
    element->Attribute("ScreenSizeX", &val);
    screenX=val;
    element->Attribute("ScreenSizeY", &val);
    screenY=val;

    //fullscreen on/off
    element->Attribute("bFullScreen", &val);
    bFullscreen=bool(val);

    backgroundTex=element->Attribute("BackgroundTex");


    //FBOs on/off
    mStr=element->Attribute("bUseFBO", &val);
    bUseFBO=bool(val);

    //shadows on/off
    mStr=element->Attribute("bRenderShadow", &val);
    bRenderShadow=bool(val);

    //scene Render on/off
    mStr=element->Attribute("bRenderSceneTexture", &val);
    bRenderSceneTexture=bool(val);

    //stereo Render on/off
    mStr=element->Attribute("bRenderStereo", &val);
    bRenderStereo=bool(val);



    //rendertarget texture resolutions
    element->Attribute("ShadowSize", &val);
    shadow_size=val;
    element->Attribute("SceneSize", &val);
    scene_size=val;
    element->Attribute("StereoSize", &val);
    leftEye_size=val;
    rightEye_size=val;


    element->Attribute("MouseSensitivity", &dVal);
    mouseSensitivity=dVal;
    element->Attribute("MoveSpeed", &dVal);
    moveSpeed=dVal;

    element->Attribute("FOV", &dVal);
    fov=dVal;

    //loading basic content
    library=element->Attribute("Library");
    startSceneFilename=element->Attribute("StartSceneFile");

    cout << startSceneFilename << endl;
}


//************************************************************
//
//  Setting up and calling all Actors' update function
//
//************************************************************

void Renderer::setup(){

    //generate Class and Type Lists
    fillGlobalLists();

    //checking for extensions and shaders:
    if (!GLEE_ARB_point_sprite)
      std::cout << " not supporting point sprites \n";
    if (!(GLEE_ARB_vertex_shader && GLEE_ARB_fragment_shader))
      std::cout << "GLSL unsupported \n";
    // and framebuffer  objects
     // verify FBOs are supported (otherwise we get FuBar'd Objects)
    if (!glutExtensionSupported ("GL_EXT_framebuffer_object") )
        cerr << "FBO extension unsupported \n";
    if (!GLEE_ARB_texture_float)
      std::cout << " not supporting floating point textures\n";



    FreeImage_Initialise();

    dWorldSetQuickStepNumIterations(physicsWorld,50);

    input->setup();          //controller gets created here!



    //setting up menu
    cout << "setting up menu" << endl;
    content= new Content;
    content->setup();               //everything menu gets set up here!


    //this is setting up the menu - I don't want to make this xml based now, it's too complicated

    cout << "loading basic stuff..." << endl;
    input->loadAll(startSceneFilename);
    cout << "finished loading basic stuff" << endl;


    //background Color
    glClearColor(backgroundColor.r,backgroundColor.g,backgroundColor.b,backgroundColor.a);

    //frame buffer objects
    if (bUseFBO){
        createFBO(&shadow_fb, &shadow_tx, &shadow_db, shadow_size, true, "shadowTexture");
        createFBO(&depth_fb, &depth_tx, &depth_db, scene_size, false, "depthTexture");
        createFBO(&scene_fb, &scene_tx, &scene_db, scene_size, false, "sceneTexture");
        createFBO(&leftEye_fb, &leftEye_tx, &leftEye_db, leftEye_size, false, "leftEyeTexture");
        createFBO(&rightEye_fb, &rightEye_tx, &rightEye_db, rightEye_size, false, "rightEyeTexture");
        }

    //throws OGL error
    if (GLEE_ARB_multitexture){
        glEnable(GL_ARB_multitexture);
        cout << "supporting multitexture" << endl;
        }

    //enable Blending for everyone!
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);


    /*
     *  Enable Hardware Point Sprites throughout
     */

    //Set upPoint sprite textures,
    glPointParameteri(GL_POINT_SPRITE_COORD_ORIGIN, GL_LOWER_LEFT);
    glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE );
    //Enable Vertex Shader point-size control
    glEnable( GL_VERTEX_PROGRAM_POINT_SIZE );


    //always enable (if disabling, re-enable afterwards!

    glEnable(GL_DEPTH_TEST);
    glEnable(GL_TEXTURE);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    //glEnable(GL_MULTISAMPLE);   //just in case we force multisampling


    glutMainLoop();
}

void Renderer::loadActor(string fileName){

    glutSetCursor(GLUT_CURSOR_NONE);

    TiXmlDocument doc( fileName );

    if (!doc.LoadFile())
        {
        cout << "there was an error!" << endl;
        return;
        }

    cout << "Loading..." <<endl;

    //load an actor...
    TiXmlHandle hDoc(&doc);
    TiXmlElement * myInfo;

    myInfo=hDoc.FirstChildElement().Element();
    // should always have a valid root but handle gracefully if it doesn't
    if (!myInfo) return;

    TiXmlHandle hRoot(0);
    // save this for later
    hRoot=TiXmlHandle(myInfo);

    TiXmlElement* element=hRoot.FirstChild( "Actor" ).Element();
    string myType;
    for( ; element!=NULL; element=element->NextSiblingElement())
	  {
      cout << element->Value() << " " << element->GetText() <<endl;
	  myType=element->GetText();
	  Actor * A=actorInfo[myType].actorReference;
	  A->create();
      A=actorList.back();
      //***********************************************************************
      //Fill up Properties
      //***********************************************************************
      A->load(element);
      }
}

void Renderer::createFBO(GLuint* fbObject, GLuint* fbTexture, GLuint* fbDepth, int fbSize, bool bDepth, string name){
    //-------------------------------------------------------
    // framebuffer object

    // create fbo and attach texture to ti
    glGenFramebuffersEXT (1, fbObject);
    glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, *fbObject);

    //set up renderbuffer
    glGenRenderbuffersEXT(1, fbDepth);

    if (!bDepth){
        glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, *fbDepth);
        glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, fbSize, fbSize);
        glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, *fbDepth);
        }
    // create the texture we'll use for the shadow map
    glGenTextures(1, fbTexture);
    glBindTexture(GL_TEXTURE_2D, *fbTexture);

    if (bDepth){

        glTexImage2D (GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, fbSize, fbSize, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
            float borderColor[] = { 1.0f, 1.0f, 1.0f, 1.0f };
            glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR,borderColor);
            // set up hardware shadow mapping
            //this is needed to get good results for shadow2DProj
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);

            //this is needed to read a texture2D from a DepthMap!
            //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);

            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
        glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, *fbTexture, 0);
    }
    else{
        cout << "no depth in FBO!" << endl;
        // attach colorBuffer to a texture
        //if (name=="depthTexture")
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F_ARB,  fbSize, fbSize, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
        //else
        //    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,  fbSize, fbSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);

        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, *fbTexture, 0);
    }


    if (bDepth){
        glDrawBuffer (GL_NONE);
        glReadBuffer (GL_NONE);
    }

    // verify all is well and restore state
    checkFBOStatus();
    glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
    glBindTexture (GL_TEXTURE_2D, 0);

    textureList[name]=new textureObject;
    textureList[name]->texture=(uint)*fbTexture;
    textureList[name]->nextTexture="NULL";
    textureList[name]->frameRate=0;

    if (bDepth)
      textureList[name]->bAlpha=true;
    else
      textureList[name]->bAlpha=false;

    textureList[name]->bWrap=false;
    textureList[name]->texFilename="NULL";

    //-------------------------------------------------------
    //end framebuffer object

    //TODO: set up two (or more!) texture channels!

}

void Renderer::checkFBOStatus(){

    GLenum status = glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT);
    switch (status){
        case GL_FRAMEBUFFER_COMPLETE_EXT:
            break;
        case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
            cerr << "FBO configuration unsupported" << endl;
            break;
        case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
            cerr << "FBO DrawBuffer incomplete" << endl;
            break;
        default:
            cerr << "FBO programmer error" << endl;
            break;
    }
}


void Renderer::update(){

for (unsigned int i=0;i<actorList.size();i++)
  actorList[i]->update(deltaTime);

for (unsigned int i=0;i<helperList.size();i++)
  helperList[i]->update(deltaTime);

for (unsigned int i=0;i<buttonList.size();i++)
  buttonList[i]->update(deltaTime);

input->update(deltaTime);

draw();

if (bUpdatePhysics)
  physicsUpdate();
}


void Renderer::physicsUpdate(){

	// Detect collision
	dSpaceCollide(collisionSpace,NULL,&Renderer::handleCollisionBetween);

	// Step world
	if (physicsTime<1)
	  physicsTime+=deltaTime;
    else
      {
      dWorldQuickStep(physicsWorld, physicsTime*0.001);
      //super-accurate but sloooooow:
	  //dWorldStep(physicsWorld,0.01f);

	  // Remove all temporary collision joints now that the world has been stepped
	  dJointGroupEmpty(jointGroup);
      physicsTime=deltaTime;
	  }

}

void Renderer::handleCollisionBetween(void * data, dGeomID o0, dGeomID o1){

		// Create an array of dContact objects to hold the contact joints

		static const int MAX_CONTACTS = 10;
		dContact contact[MAX_CONTACTS];

		for (int i = 0; i < MAX_CONTACTS; i++)
		{
			contact[i].surface.mode = dContactBounce | dContactSoftCFM;
			contact[i].surface.mu = dInfinity;
			contact[i].surface.mu2 = 0;
			//TODO: played around with Physics...
			//contact[i].surface.bounce = 0.8;

			contact[i].surface.bounce = 0.1;

			//contact[i].surface.bounce_vel = 0.1;

			contact[i].surface.bounce_vel = 0.01;

            //contact[i].surface.soft_cfm = 0.01;
			contact[i].surface.soft_cfm = 0.1;
		}
		if (int numc = dCollide(o0, o1, MAX_CONTACTS, &contact[0].geom, sizeof(dContact)))
		{
			// Get the dynamics body for each geom
			dBodyID b1 = dGeomGetBody(o0);
			dBodyID b2 = dGeomGetBody(o1);
			// To add each contact point found to our joint group we call dJointCreateContact which is just one of the many
			// different joint types available.
			for (int i = 0; i < numc; i++)
			{
				// dJointCreateContact needs to know which world and joint group to work with as well as the dContact
				// object itself. It returns a new dJointID which we then use with dJointAttach to finally create the
				// temporary contact joint between the two geom bodies.
				dJointID c = dJointCreateContact(Renderer::rendererInstance->physicsWorld, Renderer::rendererInstance->jointGroup, contact + i);
				dJointAttach(c, b1, b2);
			}
		}

}


//************************************************************
//
//  Drawing to the screen - Actors, Buttons and RenderToTexture
//
//************************************************************


void Renderer::setupCamera(bool bCalculateMatrices){

//setup Projection
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
	gluPerspective(fov,(screenY==0)?(1):((float)screenX/screenY),nearClip,farClip);


//setup camera
	glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(  input->controller->controlledActor->location.x, input->controller->controlledActor->location.y, input->controller->controlledActor->location.z,
                input->controller->lookPoint.x, input->controller->lookPoint.y, input->controller->lookPoint.z,
                input->controller->upPoint.x, input->controller->upPoint.y,input->controller->upPoint.z);

    if (bCalculateMatrices){
        glGetFloatv(GL_PROJECTION_MATRIX,projectionMatrix);
        glGetFloatv(GL_MODELVIEW_MATRIX,cameraMatrix);
        inverseCameraMatrix=cameraMatrix.inverse();
        //inverseCameraMatrix=cameraMatrix.transpose();
    }

}



void Renderer::draw(){

	glClearColor(0.5,0.5,0.5,1.0);

	glClear( GL_COLOR_BUFFER_BIT |
			 GL_DEPTH_BUFFER_BIT );

    glEnable(GL_DEPTH_TEST);

    glEnable(GL_TEXTURE);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);

//    setupCamera(true);
    glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0,screenX,screenY,0,-1,1);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
    glActiveTexture(GL_TEXTURE0);

    drawBackground();

    //do the same for FBO
    if (bRenderSceneTexture){
        glPushAttrib(GL_VIEWPORT_BIT);

        glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, scene_fb);
        glBindRenderbufferEXT (GL_RENDERBUFFER_EXT,scene_db);
        glClear( GL_COLOR_BUFFER_BIT |
                 GL_DEPTH_BUFFER_BIT );

        glViewport (0, 0, scene_size, scene_size);

        drawBackground();

        glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
        glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, 0);
        glPopAttrib();
    }



	/*
	 *	render realtime shadow mapping
	 */

    drawShadows();

    /*
	 *	transmit light location
	 */

	glLightfv(GL_LIGHT0,GL_POSITION,lightLoc);

    /*
	 *	setup camera - projection and modelView matrices
	 */

    setupCamera(true);


    /*
	 *	calculate Shadow Texture
	 */

    applyShadows();


    /*
	 *	bind shadow and depth
	 */

    setupPostProTextures();

    /*
	 *	render to FBO
	 */

    drawSceneTexture();

    if (bRenderStereo)
        drawStereoscopic();
    else{
        glMatrixMode(GL_MODELVIEW);
        draw3D();
        }


    /*
	 *	finally, draw Markers
	 */


   for (int i=0;i<(int)input->selectionMarkers.size();i++){
        drawActor(input->selectionMarkers[i]);
   }


	/////////////////////////////////////////////////////
    /// 2D Elements from here
    /////////////////////////////////////////////////////

    /*
	 *	Set Ortho viewing transformation
	 */

    glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0,screenX,screenY,0,-1,1);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
    glActiveTexture(GL_TEXTURE0);


	/*
	 *	Draw all Debug Info
	 */

    setupShading("font");
    input->displayDebug();

    //draw Stereo Buffers
    if(bRenderStereo){
        //glViewport(screenX,0,screenX,screenY);
        glViewport(0,0,screenX,screenY);
        //TODO: should be drawSFX
        drawButton(leftEyeFBO);
        //glViewport(2*screenX,0,screenX,screenY);
        glViewport(screenX,0,screenX,screenY);
        //TODO: should be drawSFX
        drawButton(rightEyeFBO);

        //reset viewport
        glViewport(0,0,screenX,screenY);
    }


	/*
	 *	Draw all Buttons
	 */

	draw2D();

    glutSwapBuffers();
    frames++;
    deltaTime=glutGet(GLUT_ELAPSED_TIME)-currentTime;
    currentTime=glutGet(GLUT_ELAPSED_TIME);
}

void Renderer::drawShadows(){

    if (!bRenderShadow || !bUseFBO)
        return;

    glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, shadow_fb);
    //glClearColor(0,0,0,1);
    glClear(GL_DEPTH_BUFFER_BIT);

	glPushAttrib(GL_VIEWPORT_BIT);
    glShadeModel(GL_FLAT);
    glViewport (0, 0, shadow_size, shadow_size);

    //setup projection
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    glPushMatrix();

        gluPerspective(90.0f, 1.0f, 1.0f, 100.0f);             //this sets the framing of the light!
        glGetFloatv(GL_PROJECTION_MATRIX, lightProjectionMatrix);

        //setup camera
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        glPushMatrix();

            gluLookAt( lightLoc.x, lightLoc.y, lightLoc.z,
            1.0f, 1.0f, 1.0f,
            0.0f, 1.0f, 0.0f);

            //save both matrices
            glGetFloatv(GL_MODELVIEW_MATRIX, lightViewMatrix);
            glPolygonOffset(4.1f, 8.0f);

            //only draw back faces into shadow map
            //for some reason, just using polygon offset doesnt work
            //glCullFace(GL_FRONT);
            //glEnable(GL_CULL_FACE);
            glColorMask(0, 0, 0, 0);// disable the color drawing
            glEnable(GL_POLYGON_OFFSET_FILL);

            bUpdateTransform=false;
                draw3D();
            bUpdateTransform=true;

            glDisable(GL_POLYGON_OFFSET_FILL);
            //glDisable(GL_CULL_FACE);
            glShadeModel(GL_SMOOTH);

            glColorMask(1,1,1,1);
            glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);

        glPopMatrix();

    glMatrixMode(GL_PROJECTION);
    glPopMatrix();

    glPopAttrib (); // restore the viewport

    glClear(GL_DEPTH_BUFFER_BIT);
 }



void Renderer::applyShadows(){

    if (!bRenderShadow)
        return;

//one way...
    glActiveTexture(GL_TEXTURE1);

	float x[] = { 1.0f, 0.0f, 0.0f, 0.0f };
    float y[] = { 0.0f, 1.0f, 0.0f, 0.0f };
    float z[] = { 0.0f, 0.0f, 1.0f, 0.0f };
    float w[] = { 0.0f, 0.0f, 0.0f, 1.0f };

	//unused?
	/*
	const GLfloat bias[] = {0.5f, 0.0f, 0.0f, 0.0f,
				 			 0.0f, 0.5f, 0.0f, 0.0f,
							 0.0f, 0.0f, 0.5f, 0.0f,
							 0.5f, 0.5f, 0.5f, 1.0f};
    */

    glTexGenfv( GL_S, GL_EYE_PLANE, x );
    glTexGenfv( GL_T, GL_EYE_PLANE, y );
    glTexGenfv( GL_R, GL_EYE_PLANE, z );
    glTexGenfv( GL_Q, GL_EYE_PLANE, w );

    glTexGeni( GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
    glTexGeni( GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
    glTexGeni( GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
    glTexGeni( GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );

	glEnable( GL_TEXTURE_GEN_S );
    glEnable( GL_TEXTURE_GEN_T );
    glEnable( GL_TEXTURE_GEN_R );
    glEnable( GL_TEXTURE_GEN_Q );

    // Set up the depth texture projection
	// !!!ATTENTION!!!
	// Note again that the multiplication order is different in OpenGL than in Direct3D
	// In Direct3D you'd do the following: bias * m_LookAtMatrix * m_lightProjection
	// In OpenGL you do this: bias * m_lightProjection * m_LookAtMatrix
    glMatrixMode (GL_TEXTURE);

    glLoadIdentity();
    glTranslatef(0.5,0.5,0.5);
    glScalef(0.5,0.5,0.5);
    glMultMatrixf(lightProjectionMatrix);
    glMultMatrixf(lightViewMatrix);

    //and now the inverse of the cameraMatrix
    glMultMatrixf(inverseCameraMatrix);

    glActiveTexture(GL_TEXTURE0);
    glMatrixMode(GL_MODELVIEW);

}

void Renderer::drawSceneTexture(){


    glPushAttrib(GL_VIEWPORT_BIT);

    //DepthPass
    glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, depth_fb);
    glBindRenderbufferEXT (GL_RENDERBUFFER_EXT,depth_db);

    glClearColor(65536.0,65536.0,65536.0,65536.0);
    glClear( GL_COLOR_BUFFER_BIT |
			 GL_DEPTH_BUFFER_BIT );

    glViewport (0, 0, scene_size, scene_size);

    bDepthPass=true;
    bIncludeShadows=false;

    draw3D();


    glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
    glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, 0);

    glClearColor(backgroundColor.r,backgroundColor.g,backgroundColor.b,backgroundColor.a);

    bDepthPass=false;
    bIncludeShadows=true;

    //Color Pass

    glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, scene_fb);
    glBindRenderbufferEXT (GL_RENDERBUFFER_EXT,scene_db);

    glViewport (0, 0, scene_size, scene_size);

    draw3D();

    glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
    glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, 0);
    glPopAttrib();

    //now draw the resulting image into a quad!
}

void Renderer::drawStereoscopic(){

    float right, left;

    right=screenX/screenY * frustumTop;
    left=screenX/screenY * frustumBottom;

    glPushAttrib(GL_VIEWPORT_BIT);

    /***********************************************************
    Left Eye
    ************************************************************/

    glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, leftEye_fb);
    glBindRenderbufferEXT (GL_RENDERBUFFER_EXT,leftEye_db);
    glClear( GL_COLOR_BUFFER_BIT |
			 GL_DEPTH_BUFFER_BIT );

    glViewport (0, 0, leftEye_size, leftEye_size);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    float nleft, nright;

    nright=right - (-0.0075 * right);                   //Thanks to Flocki for the magic numbers
    nleft =left  - (-0.0075 * right);

    glFrustum(nleft, nright, frustumBottom, frustumTop, nearClip, farClip);
    glTranslatef(eyeDistance,0,0);

    glMatrixMode(GL_MODELVIEW);
    draw3D();
    glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
    glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, 0);


    /***********************************************************
    Right Eye
    ************************************************************/

    glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, rightEye_fb);
    glBindRenderbufferEXT (GL_RENDERBUFFER_EXT,rightEye_db);
    glClear( GL_COLOR_BUFFER_BIT |
			 GL_DEPTH_BUFFER_BIT );

    glViewport (0, 0, rightEye_size, rightEye_size);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    nright=right - (0.0075 * right);
    nleft =left  - (0.0075 * right);

    glFrustum(nleft, nright, frustumBottom, frustumTop, nearClip, farClip);
    glTranslatef(-eyeDistance,0,0);

    glMatrixMode(GL_MODELVIEW);
    draw3D();
    glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
    glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, 0);

    glPopAttrib (); // restore the viewport
}



void Renderer::draw3D(){


    glActiveTexture(GL_TEXTURE0);

    if (!bCollisionOnly){
        //draw color
        for (int i=0;i<(int)actorList.size(); i++){
            if (!actorList[i]->bHidden){
                drawActor(actorList[i]);
            }
        }
    }

    //reset texture Matrix transform
    glMatrixMode(GL_TEXTURE);
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);

    if (!Control::bRunning){

        setupShading("color");
        for (unsigned int i=0;i<actorList.size();i++)
            if (!actorList[i]->bHidden && !(actorList[i]->drawType==DRAW_PLANE || actorList[i]->drawType==DRAW_CUBE || actorList[i]->drawType==DRAW_TEA)) drawHelper(actorList[i]);
    }

}

void Renderer::draw2D(){

    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
    glDepthMask(GL_TRUE);

    //colored Buttons  first

    for (unsigned int i=0;i<buttonList.size();i++){
        if (    (!Control::bRunning || buttonList[i]->bScreenOverlay)
                && !buttonList[i]->bHidden){

                    drawButton(buttonList[i]);

                }
    }

    //finally font rendering
    setupShading("font");

    for (unsigned int i=0;i<buttonList.size();i++){
        if (    (!Control::bRunning || buttonList[i]->bScreenOverlay)
                && !buttonList[i]->bHidden){

        buttonList[i]->drawTooltip();
        }
    }
}

void Renderer::drawBackground(){

setupShading("texture");
glEnable(GL_TEXTURE_2D);
glDepthMask(GL_FALSE);

//do for all FBOs too!

if (backgroundTex!="")
  glBindTexture(GL_TEXTURE_2D, textureList[backgroundTex]->texture);

    glColor4f(1.0,1.0,1.0,1.0);

    glBegin(GL_POLYGON);
        glTexCoord2f(0.0,0.0);
		glVertex3f(0,0,.0);
        glTexCoord2f(1.0,0.0);
		glVertex3f(input->screenX,0,0.0);
        glTexCoord2f(1.0,1.0);
		glVertex3f(input->screenX,input->screenY,0.0);
        glTexCoord2f(0.0,1.0);
		glVertex3f(0,input->screenY,0.0);
	glEnd();

glDepthMask(GL_TRUE);
//glDisable(GL_BLEND);
}


void Renderer::drawButton(msbButton::Button* b){

    glDisable(GL_DEPTH_TEST);

    //set Shader
    setupShading(b->sceneShaderID);
    b->updateShaders();

    //set Texture
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, textureList[b->textureID]->texture);

    glPushMatrix();

    //buttons only translate
    glTranslatef(b->location.x,b->location.y,b->location.z);

    //draw
    //TODO:phase out...
    b->drawPlane();
    //drawPlane(0.0, 0.0, b->scale.x, b->scale.y, b->color);

    glPopMatrix();

    glEnable(GL_DEPTH_TEST);

}

void Renderer::drawActor(Actor* a){

    //shader
    if (bDepthPass) setupShading(a->depthShaderID);
    else setupShading(a->sceneShaderID);

    a->updateShaders();

    if (a->bTextured)
        setupTexturing(a->textureID, a);

    //alpha blending
    glBlendFunc(a->blendModeOne,a->blendModeTwo);

    //z-test
    if (!a->bZTest) glDepthMask(GL_FALSE);

    //start translating
    glPushMatrix();

    //translate according to base
    if (bUpdateTransform)
        transformActorMatrix(a);
    else
        glLoadMatrixf(a->baseMatrix);

    //set Color
    glColor4f(a->color.r,a->color.g,a->color.b,a->color.a);

    //Actual Drawing takes place here!
        if (a->drawType==DRAW_PLANE)           drawPlane(0.0,0.0,a->scale.x, -a->scale.y, a->color );
        else if (a->drawType==DRAW_VBOMESH)    drawColladaMesh(vboList[a->vboMeshID]);
        else if (a->drawType==DRAW_PARTICLES || a->drawType==DRAW_PARTICLES_LINE || a->drawType==DRAW_PARTICLES_PATH) a->drawParticles();                 //Particles
        else if (a->drawType==DRAW_SPRITE)     a->drawSprite();
        else if (a->drawType==DRAW_CUBE)       drawCube(a->scale.x);                 //Mesh
        else if (a->drawType==DRAW_TEA)        a->drawTeapot();
        else if (a->drawType==DRAW_SKELETAL)   drawColladaMesh(vboList[a->vboMeshID]);

    if (!a->bZTest) glDepthMask(GL_TRUE);

    //end translation
    glPopMatrix();
}

void Renderer::drawHelper(Actor* a){


    if ( a->drawType==DRAW_SKELETAL){
        setupShading(a->sceneShaderID);
        a->updateShaders();
    }

    glPushMatrix();
    glLoadMatrixf(a->baseMatrix);

    glColor3f(1.0, 1.0, 1.0);

    //Actual Drawing takes place here!
    if (a->drawType==DRAW_PLANE)            drawPlane(0.0,0.0,a->scale.x, -a->scale.y, a->color );
    else if (a->drawType==DRAW_SKELETAL)    drawColladaMesh(vboList[a->vboMeshID]);
    else                                    drawCube(a->scale.x);

    a->drawOrientation();
    glPopMatrix();

    //turn back to color
    if ( a->drawType==DRAW_SKELETAL){
        setupShading("color");
    }
}



void Renderer::drawCube(float scale){


glutSolidCube( min(max(scale, 0.5f), 1.0f) / max(scale, 1.0f) );
}

void Renderer::drawPlane(float x1,float  y1,float  x2,float  y2, Vector4f color){

        GLfloat verts[] = { x1, y1,
                            x1, y2,
                            x2, y2,
                            x2, y1 };

		GLfloat tex_coords[] = { 0, 0,
                                 0, 1,
                                 1, 1,
                                 1, 0 };

        GLfloat normals[] = { 0, 0, 1,
                              0, 0, 1,
                              0, 0, 1,
                              0, 0, 1 };
        GLfloat vColor[] ={ color.r, color.g, color.b, color.a,
                            color.r, color.g, color.b, color.a,
                            color.r, color.g, color.b, color.a,
                            color.r, color.g, color.b, color.a };

        glEnableClientState( GL_VERTEX_ARRAY );
        glEnableClientState( GL_TEXTURE_COORD_ARRAY );
        glEnableClientState( GL_NORMAL_ARRAY );
        glEnableClientState( GL_COLOR_ARRAY);

		glTexCoordPointer(2, GL_FLOAT, 0, tex_coords );
		glVertexPointer(2, GL_FLOAT, 0, verts );
        glNormalPointer(GL_FLOAT, 0, normals );
        glColorPointer(4,GL_FLOAT,0, vColor);

		glDrawArrays( GL_TRIANGLE_FAN, 0, 4 );

        glDisableClientState( GL_VERTEX_ARRAY );
		glDisableClientState( GL_TEXTURE_COORD_ARRAY );
        glDisableClientState( GL_COLOR_ARRAY);
        glDisableClientState( GL_NORMAL_ARRAY );


}

void Renderer::setupShading(string shaderName){

    if (shaderName!=lastShader && shaderList[shaderName]){
        glUseProgram(shaderList[shaderName]->shader);
        lastShader=shaderName;
        }
    if (!shaderList[shaderName])
        cout << "found bad shader: " << shaderName << endl;

}

void Renderer::setupTexturing(string texName, Actor* a){

    //texturing
    glBindTexture(GL_TEXTURE_2D, textureList[texName]->texture);

    if (!a)
        return;

    //texture animation
    if (textureList[texName]->nextTexture!="NULL" && currentTime - a->textTimer > textureList[texName]->frameRate ){
        a->textTimer += textureList[texName]->frameRate;
        a->textureID=textureList[texName]->nextTexture;
        }

    transformTextureMatrix(a);
}

void Renderer::setupPostProTextures(){

    if (bUseFBO){
        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_2D, textureList["shadowTexture"]->texture);

        glActiveTexture(GL_TEXTURE2);
        glBindTexture(GL_TEXTURE_2D, textureList["depthTexture"]->texture);
    }
}

void Renderer::transformActorMatrix(Actor* a){

//translate according to base
    if (a->base)
        glLoadMatrixf(a->base->baseMatrix);

    //translate according to location
    if (a->bUseTransformMatrix){
        glMultMatrixf(a->originalMatrix);
        glMultMatrixf(a->transformMatrix);
        }
    else{
        glTranslatef(a->location.x,a->location.y,a->location.z);
        //translate to pivot
        glTranslatef(a->pivotLocation.x,a->pivotLocation.y,a->pivotLocation.z);
        //rotate
        //changed to Yaw-Pitch-Roll
        glRotatef(a->rotation.y,0,1,0);
        glRotatef(a->rotation.x,1,0,0);
        glRotatef(a->rotation.z,0,0,1);
        //translate back for drawing
        glTranslatef(-a->pivotLocation.x,-a->pivotLocation.y,-a->pivotLocation.z);
        if (a->drawType!=DRAW_PLANE)
            glScalef(a->scale.x, a->scale.y, a->scale.z);
        }
    //update our BaseMatrix
    glGetFloatv(GL_MODELVIEW_MATRIX,(GLfloat *) &a->baseMatrix);

    //calculations for the orientation vector
    Matrix4f interimMatrix;
    glTranslatef(0,0,1);
    glGetFloatv(GL_MODELVIEW_MATRIX,(GLfloat *) &interimMatrix);
    glTranslatef(0,0,-1);

    interimMatrix=interimMatrix-a->baseMatrix;
    a->orientation=interimMatrix.getTranslation();
}

void Renderer::transformTextureMatrix(Actor* a){

    glActiveTexture(GL_TEXTURE0);
    glMatrixMode( GL_TEXTURE );
    glLoadIdentity();

        // make changes to the texture
        glTranslatef(a->texTranslation.x,a->texTranslation.y,a->texTranslation.z);

        glRotatef(a->texRotation.x,1,0,0);
        glRotatef(a->texRotation.y,0,1,0);
        glRotatef(a->texRotation.z,0,0,1);

        glScalef(a->texScale.x,a->texScale.y,a->texScale.z);

    glMatrixMode(GL_MODELVIEW);
}

//************************************************************
//
//Picking: determining what Actor the mouse points to
//         and mouse 3d coordinate
//
//************************************************************


//picking needs mouse coordinates
void Renderer::pick(int x, int y){

    //needs mouse coordinates
	GLint viewport[]={0,0,screenX,screenY};

    //set input->mouse3d to very very far away, in case we point into nirvana!
    input->mouse3D=Vector3f(1000000,1000000,1000000);

	glSelectBuffer(BUFSIZE,selectBuf);
	glRenderMode(GL_SELECT);
    glInitNames();

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPickMatrix(x,viewport[3]-y,3,3,viewport);
    glMultMatrixf(projectionMatrix);

	glMatrixMode(GL_MODELVIEW);
    glLoadMatrixf(cameraMatrix);

    //bUpdateTransform=false;

    setupShading("color");

    glShadeModel(GL_FLAT);
    for (unsigned int i=0; i<actorList.size(); i++)
      {
      if (actorList[i]->bPickable)
       {
       glPushName(i);
	    glPushMatrix();
         //actorList[i]->drawCollision();
         drawHelper(actorList[i]);//->drawCollision();
        glPopMatrix();
       glPopName();
       }
      }
    glShadeModel(GL_SMOOTH);
	int hits;

	glFlush();        //force Render

	// returning to normal rendering mode
	hits = glRenderMode(GL_RENDER);

	// if there are hits process them
	if (hits != 0)
	   processHits(hits,selectBuf,x,y);

    glMatrixMode(GL_MODELVIEW);
}

void Renderer::processHits (GLint hits, GLuint buffer[], int cursorX, int cursorY){

    double minZ=connectHits(hits,buffer);

    GLint viewport[]={0,0,screenX,screenY};
	GLdouble modelview[16];
	GLdouble projection[16];
	GLdouble winX, winY, winZ;
	GLdouble posX, posY, posZ;

    for (int i=0;i<16;i++){
        modelview[i]=cameraMatrix.data[i];
        projection[i]=projectionMatrix.data[i];
    }

	winX = cursorX;
	winY = viewport[3] - (float)cursorY;
    winZ = minZ/pow(2.0f,32.0f);  //from the Z-Buffer

	gluUnProject( winX, winY, winZ, modelview, projection, viewport, &posX, &posY, &posZ);

    input->mouse3D.x=posX;
    input->mouse3D.y=posY;
    input->mouse3D.z=posZ;
}

double Renderer::connectHits(GLint hits, GLuint buffer[]){
    //determine the length of the buffer
    //unused!
//    int length=sizeof (buffer);
    int numberOfNames=0;
    int i=0;                   //buffer pointer
    int actorListPlace=0;      //reference to the actor list
    double minZ=0.0f;           //minimum Z coordinate of the hit
    double maxZ=0.0f;           //maximum Z coordinate of the hit
    double smallestZ=0.0f;      //smallest Z coordinate of the hit
    Actor *mouseActor=NULL;         //actor pointer that was hit
    Actor *nearestActor=NULL;         //actor pointer that was hit
    //determine the actor

    //while still stuff in the buffer:
    for (int h=0;h<hits;h++)
    {
     //get the number of names
       numberOfNames=buffer[i++];  //i = 1
       minZ=buffer[i++];         //i = 2
       maxZ=buffer[i++];         //i = 3

       if (smallestZ==0.0f)
         smallestZ=minZ+1000;

       //determine actor by hit
       actorListPlace=buffer[i];

       if (actorListPlace>=(int)actorList.size()){
            mouseActor=helperList[actorListPlace- actorList.size()];
            }
       else
            mouseActor=actorList[actorListPlace];

       //see if this hit is the closest to the camera
       if (minZ<smallestZ)
         {
         nearestActor=mouseActor;
         smallestZ=minZ;
         }
       //advance buffer to next hit
       buffer+=numberOfNames;
    }
    input->worldTarget=nearestActor;
    return smallestZ;
}

//************************************************************
//
//       Texture and Shader Loading and Initialisation functions
//
//
//************************************************************

//generates a texture from a RAW file - needs implementation of textureList!
GLuint Renderer::LoadTextureRAW( const char * filename,int size, int wrap ){

    GLuint texture;
    int width, height;
    BYTE * data;
    FILE * file;

    // open texture data
    file = fopen( filename, "rb" );
    if ( file == NULL ) return 0;

    // allocate buffer
    width = size;
    height = size;
    data = (BYTE*) malloc( width * height * 3 );

    // read texture data
    fread( data, width * height * 3, 1, file );
    fclose( file );

    //allocate texture List
    glGenTextures( 1, &texture );

    // select our current texture
    glBindTexture( GL_TEXTURE_2D, texture );

    // select modulate to mix texture with color for shading
    glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );

    // when texture area is small, bilinear filter the closest mipmap
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
                     GL_LINEAR_MIPMAP_NEAREST );
    // when texture area is large, bilinear filter the first mipmap
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

    // if wrap is true, the texture wraps over at the edges (repeat)
    //       ... false, the texture ends at the edges (clamp)
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
                     wrap ? GL_REPEAT : GL_CLAMP );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
                     wrap ? GL_REPEAT : GL_CLAMP );

    // build our texture mipmaps
    gluBuild2DMipmaps( GL_TEXTURE_2D, 3, width, height,
                       GL_RGB, GL_UNSIGNED_BYTE, data );

    // free buffer
    free( data );

    return texture;
}

bool Renderer::LoadTextureTGA( string filename, bool wrap, bool bAlpha, string texID ){

    GLuint texture;

    FIBITMAP * myBitmap = FreeImage_Load(FIF_TARGA,filename.c_str(),0);

    FreeImage_FlipVertical(myBitmap);

    //allocate texture List
    glGenTextures( 1, &texture );

    // select our current texture
    glBindTexture( GL_TEXTURE_2D, texture );

    // when texture area is small, bilinear filter the closest mipmap
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR );
    // when texture area is large, bilinear filter the first mipmap
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

    // if wrap is true, the texture wraps over at the edges (repeat)
    //       ... false, the texture ends at the edges (clamp)
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap ? GL_REPEAT : GL_CLAMP );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap ? GL_REPEAT : GL_CLAMP );

    // build our texture and mipmaps
    if (bAlpha)
      glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, FreeImage_GetWidth(myBitmap), FreeImage_GetHeight(myBitmap), 0, GL_BGRA, GL_UNSIGNED_BYTE, FreeImage_GetBits(myBitmap) );
    else
      glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, FreeImage_GetWidth(myBitmap), FreeImage_GetHeight(myBitmap), 0, GL_BGR, GL_UNSIGNED_BYTE, FreeImage_GetBits(myBitmap) );

    FreeImage_Unload(myBitmap);

    textureList[texID]=new textureObject;
    textureList[texID]->texture=texture;
    textureList[texID]->bAlpha=bAlpha;
    textureList[texID]->bWrap=wrap;
    textureList[texID]->texFilename=filename;

    return true;
}


void Renderer::drawColladaMesh (complexMesh* myMesh){

        glPushMatrix();


        glEnableClientState(GL_VERTEX_ARRAY);

        glBindBufferARB(GL_ARRAY_BUFFER_ARB, myMesh->vertexBufferObject[0]);
        glVertexPointer(myMesh->verticesPerShapeCount, GL_FLOAT, 0, 0);

        glEnableClientState(GL_NORMAL_ARRAY);

        glBindBufferARB(GL_ARRAY_BUFFER_ARB, myMesh->normalBufferObject[0]);
        glNormalPointer(GL_FLOAT, 0, 0);



        glEnableClientState(GL_TEXTURE_COORD_ARRAY);

        glBindBufferARB(GL_ARRAY_BUFFER_ARB, myMesh->texCoordBufferObject[0]);
        glTexCoordPointer(myMesh->texCoordPerVertexCount, GL_FLOAT, 0, 0);

        //skinning from here!
        //use secondary color for weights, and limit weights to 4

        if (myMesh->bIsSkeletal){
            glEnableClientState(GL_COLOR_ARRAY);
            glEnableClientState(GL_SECONDARY_COLOR_ARRAY);

            glBindBufferARB(GL_ARRAY_BUFFER_ARB, myMesh->boneReferenceObject[0]);
            glColorPointer(4, GL_FLOAT, 0, 0);

            glBindBufferARB(GL_ARRAY_BUFFER_ARB, myMesh->vertexWeightsObject[0]);
            glSecondaryColorPointer(4, GL_FLOAT, 0, 0);
            }

        if (myMesh->bVertexColor){
            glEnableClientState(GL_COLOR_ARRAY);
            glBindBufferARB(GL_ARRAY_BUFFER_ARB, myMesh->boneReferenceObject[0]);
            glColorPointer(4, GL_FLOAT, 0, 0);
            }

        glDrawArrays(myMesh->vertexInterpretation, 0, myMesh->vertexCount[0]);

        glBindBufferARB(GL_ARRAY_BUFFER_ARB,0);

        glDisableClientState(GL_VERTEX_ARRAY);
        glDisableClientState(GL_NORMAL_ARRAY);
        glDisableClientState(GL_TEXTURE_COORD_ARRAY);

        if (myMesh->bIsSkeletal){
            glDisableClientState(GL_COLOR_ARRAY);
            glDisableClientState(GL_SECONDARY_COLOR_ARRAY);
            }
        if (myMesh->bVertexColor){
            glDisableClientState(GL_COLOR_ARRAY);
            }
    glPopMatrix();

}


bool Renderer::loadShader(string vertexShaderFileName, string fragmentShaderFileName, string shaderProgramName){

    GLuint fragmentShader;
    GLuint vertexShader;

    GLuint shaderProgram;


    char * vertexShaderFile;               //actually holds the whole file
    char * fragmentShaderFile;             //actually holds the whole file


    //setup shader
    vertexShader=glCreateShader(GL_VERTEX_SHADER);
    fragmentShader=glCreateShader(GL_FRAGMENT_SHADER);

    cout << fragmentShaderFileName << "\n";
    vertexShaderFile=textFileRead((char*)vertexShaderFileName.c_str());
    fragmentShaderFile=textFileRead((char*)fragmentShaderFileName.c_str());

    const char* ptrV = vertexShaderFile;
    const char* ptrF = fragmentShaderFile;

    glShaderSource(vertexShader, 1, &ptrV,NULL);
    glShaderSource(fragmentShader, 1, &ptrF,NULL);

    glCompileShader(vertexShader);
    if (vertexShader==0)
      return false;

    glCompileShader(fragmentShader);
    if (fragmentShader==0)
      return false;

    printShaderInfoLog(vertexShader);
    printShaderInfoLog(fragmentShader);

    //Link shaders
    shaderProgram=glCreateProgram();
    if (shaderProgram==0)
      return false;

    glAttachShader(shaderProgram,vertexShader);
    glAttachShader(shaderProgram,fragmentShader);

    glLinkProgram(shaderProgram);
    printProgramInfoLog(shaderProgram);


    //cleanUp
    free(vertexShaderFile);
    free(fragmentShaderFile);

    shaderList[shaderProgramName]=new shaderObject;
    shaderList[shaderProgramName]->shader=shaderProgram;
    shaderList[shaderProgramName]->vertexShaderFilename=vertexShaderFileName;
    shaderList[shaderProgramName]->fragmentShaderFilename=fragmentShaderFileName;
    cout << "registered program!" << shaderProgram << "\n";
    return true;
}

void Renderer::printShaderInfoLog(GLuint obj){
    int infologLength = 0;
    int charsWritten  = 0;
    char *infoLog;

	glGetShaderiv(obj, GL_INFO_LOG_LENGTH,&infologLength);

    if (infologLength > 0)
    {
        infoLog = (char *)malloc(infologLength);
        glGetShaderInfoLog(obj, infologLength, &charsWritten, infoLog);
		printf("%s\n",infoLog);
        free(infoLog);
    }
}

void Renderer::printProgramInfoLog(GLuint obj){
    int infologLength = 0;
    int charsWritten  = 0;
    char *infoLog;

	glGetProgramiv(obj, GL_INFO_LOG_LENGTH,&infologLength);

    if (infologLength > 0)
    {
        infoLog = (char *)malloc(infologLength);
        glGetProgramInfoLog(obj, infologLength, &charsWritten, infoLog);
		printf("%s\n",infoLog);
        free(infoLog);
    }
}


